﻿using Ndns.Packet.Abstractions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Ndns.Packet.Parser
{

    static class DnsHostNameExtensions
    {
        public static int CopyTo(this DnsHostName hostName, Stream stream, ref int offset)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));

            int count = 1;
            foreach (string part in hostName.DomainParts)
            {
                byte[] encodedBytes = PunycodeHelper.EncodeDomainPartToArray(part.ToLowerInvariant());
                stream.WriteByte((byte)encodedBytes.Length);
                stream.Write(encodedBytes);
                count += encodedBytes.Length + 1;
                offset += encodedBytes.Length + 1;
            }
            stream.WriteByte(0);
            offset += 1;
            return count;
        }

        public static int CopyCompressedTo(this DnsHostName hostName, Stream stream, IDictionary<string, DnsHostNamePointer> symbols, ref int offset)
        {
            if (stream == null)
                throw new ArgumentNullException(nameof(stream));
            if (symbols == null)
                throw new ArgumentNullException(nameof(symbols));

            int originalOffset = offset;
            var buffer = new StringBuilder();

            for (int i = 0; i < hostName.DomainParts.Count; i++)
            {
                var remainingPart = ConvertDomainPartsToString(hostName, i, buffer);
                if (symbols.ContainsKey(remainingPart))
                {
                    //加入指针
                    var pointer = symbols[remainingPart];
                    pointer.WriteTo(stream);
                    offset += 2;
                    //退出
                    return offset - originalOffset;
                }
                else
                {
                    //在符号字典中记录
                    symbols.Add(remainingPart, (DnsHostNamePointer)offset);
                    //加入流
                    byte[] encodedBytes = PunycodeHelper.EncodeDomainPartToArray(hostName.DomainParts[i].ToLowerInvariant());
                    stream.WriteByte((byte)encodedBytes.Length);
                    stream.Write(encodedBytes);
                    offset += 1 * sizeof(byte) + encodedBytes.Length;
                }
            }
            //加入末尾0
            stream.WriteByte(0);
            offset++;

            return offset - originalOffset;
        }

        private static string ConvertDomainPartsToString(DnsHostName hostName, int start_index, StringBuilder buffer)
        {
            buffer.Clear();
            var domainParts = hostName.DomainParts;
            for (int i = start_index; i < domainParts.Count; i++)
            {
                buffer.Append(domainParts[i].ToLowerInvariant());
                buffer.Append('.');
            }
            return buffer.ToString();
        }
    }
}
